﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics.Contracts;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;

namespace IDI.Studio.Application
{
    public static class ObjectFactory
    {
        private const string DefaultSectionName = "UnitySection";

        private static UnityConfigurationSection _defaultUnity = GetUnitySection(DefaultSectionName);

        private static IUnityContainer _unityContainer;

        static ObjectFactory()
        {
            Initialize();
        }

        #region Private methods

        /// <summary>
        /// Initialize when application start.
        /// </summary>
        public static void Initialize()
        {
            _unityContainer = LoadUnityFromConfiguration();
        }

        /// <summary>
        /// Please note, it cannot dispose any container at this time. Otherwise, it will be failed to call Resolve.
        /// </summary>
        /// <returns></returns>
        private static IUnityContainer LoadUnityFromConfiguration()
        {
            var defaultUnityContainer = new UnityContainer();

            defaultUnityContainer.LoadConfiguration(_defaultUnity);

            IUnityContainer unityContainer = defaultUnityContainer;

            return unityContainer;
        }

        private static IUnityContainer GetContainer()
        {
            return _unityContainer;
        }

        private static UnityConfigurationSection GetUnitySection(string sectionName)
        {
            Contract.Ensures(Contract.Result<UnityConfigurationSection>() != null, "The section doesn't exist in the Web.config file.");

            return (UnityConfigurationSection)ConfigurationManager.GetSection(sectionName);
        }


        #endregion

        public static T Resolve<T>()
        {
            var unityContainer = GetContainer();

            if (unityContainer == null)
            {
                return default(T);
            }
            return unityContainer.Resolve<T>();
        }

        public static IEnumerable<T> ResolveAll<T>()
        {
            var unityContainer = GetContainer();

            if (unityContainer == null)
            {
                return new List<T>();
            }

            return unityContainer.ResolveAll<T>();
        }

        public static T Resolve<T>(string name)
        {
            Contract.Requires(!string.IsNullOrEmpty(name));

            var unityContainer = GetContainer();

            if (unityContainer == null)
            {
                return default(T);
            }
            return unityContainer.Resolve<T>(name);
        }

        public static T Resolve<T>(params ResolverOverride[] overrides)
        {
            var unityContainer = GetContainer();

            if (unityContainer == null)
            {
                return default(T);
            }
            return unityContainer.Resolve<T>(overrides);
        }

        public static object Resolve(Type type, params ResolverOverride[] overrides)
        {
            Contract.Requires(type != null);

            var unityContainer = GetContainer();

            if (unityContainer == null)
            {
                return null;
            }
            return unityContainer.Resolve(type, overrides);
        }

        public static void Teardown(object instance)
        {
            var unityContainer = GetContainer();

            if (unityContainer == null)
            {
                return;
            }
            unityContainer.Teardown(instance);
        }
    }
}
